#pragma once
#ifndef __PCODE_HPP__
#define __PCODE_HPP__
/*
    AST 转 Pcode的实现
*/

#include "semantic_part/symboltable.h"
#include <string>
#include <vector>
#include <set>

using std::vector;
using std::string;

// P-code指令
// 取立即数 | 读数 | 存数 | 调用 | 初始化栈空间 | 无条件跳转 | 有条件跳转 | 运算操作
typedef enum { INS_LIT, INS_LOD, INS_STO, INS_CAL, INS_INT, INS_JMP, INS_JPC, INS_OPR } ins_type;

// OPR支持的运算
/*
    | 过程返回 | 栈顶取负 | 栈顶取非 |   加法   |   减法   | 
    |   乘法  |   除法  |   取模   | 判断等于 | 判断不等 |
    | 判断小于 | 小于等于 | 判断大于 | 大于等于 | 输出栈顶 |
    | 输出换行 | 从命令行读取输入到栈顶
*/
typedef enum {
    AL_RET, AL_NEG, AL_NOT, AL_ADD, AL_SUB,
    AL_MUL, AL_DIV, AL_MOD, AL_EQU, AL_NEQ,
    AL_LES, AL_LEQ, AL_GTR, AL_GEQ, AL_PRT,
    AL_PNL, AL_SCN
} AL_type;

const string get_op_name(ins_type op);

// 指令
typedef struct instruction {
    ins_type OP;    // 指令
    int L;          // 层级差
    int d;          // 地址偏移/立即数/OPR指令
    bool need_fill; // false：不需要回填，true：需要回填

    instruction(ins_type op, int l, int _d, bool _need_fill=false) {
        OP = op;
        L = l;
        d = _d;
        need_fill = _need_fill;
    }
} st_ins, *st_ins_ptr;

class pcode_transformer {
private:
    vector<st_ins> target_codelines;    // 得到的指令

    // 目标地址回填
    int fill_addr(int idx_from, int idx_to, int addr, ins_type type=INS_JPC);

    // 读取AST, 返回所需要的栈空间数量
    std::set<string> read_AST(const TreeDefine* root, int cur_level, int last_node_type);

    // 针对PROGRAMHEAD/FUNCTIONHEAD/PROCEDREHEAD节点的代码生成
    std::set<string> gen_head(const TreeDefine* root, int cur_level, int last_node_type);

    // 针对PROGRAMBODY节点的代码生成
    std::set<string> gen_programbody(const TreeDefine* root, int cur_level, int last_node_type);

    // 针对EK_ID节点的代码生成
    std::set<string> gen_ek_id(const TreeDefine* root, int cur_level, int last_node_type);

    // 针对DK_VAR节点的代码生成
    std::set<string> gen_dk_var(const TreeDefine* root, int cur_level, int last_node_type);

    // 针对各种运算符的代码生成
    std::set<string> gen_plus(const TreeDefine* root, int cur_level, int last_node_type);
    std::set<string> gen_minus(const TreeDefine* root, int cur_level, int last_node_type);
    std::set<string> gen_negative(const TreeDefine* root, int cur_level, int last_node_type);
    std::set<string> gen_mul(const TreeDefine* root, int cur_level, int last_node_type);
    std::set<string> gen_div(const TreeDefine* root, int cur_level, int last_node_type);
    std::set<string> gen_mod(const TreeDefine* root, int cur_level, int last_node_type);

    std::set<string> gen_op(const TreeDefine* root, int cur_level, int last_node_type);
    std::set<string> gen_ek_const(const TreeDefine* root, int cur_level, int last_node_type);
    std::set<string> gen_func_id(const TreeDefine* root, int cur_level, int last_node_type);
    std::set<string> gen_func_sys(const TreeDefine* root, int cur_level, int last_node_type);
    std::set<string> gen_to(const TreeDefine* root, int cur_level, int last_node_type);
    std::set<string> gen_downto(const TreeDefine* root, int cur_level, int last_node_type);
    std::set<string> gen_read(const TreeDefine* root, int cur_level, int last_node_type);
    std::set<string> gen_write(const TreeDefine* root, int cur_level, int last_node_type);
    std::set<string> gen_lt(const TreeDefine* root, int cur_level, int last_node_type);
    std::set<string> gen_le(const TreeDefine* root, int cur_level, int last_node_type);
    std::set<string> gen_gt(const TreeDefine* root, int cur_level, int last_node_type);
    std::set<string> gen_ge(const TreeDefine* root, int cur_level, int last_node_type);
    std::set<string> gen_equal(const TreeDefine* root, int cur_level, int last_node_type);
    std::set<string> gen_unequal(const TreeDefine* root, int cur_level, int last_node_type);
    std::set<string> gen_not(const TreeDefine* root, int cur_level, int last_node_type);
    std::set<string> gen_or(const TreeDefine* root, int cur_level, int last_node_type);
    std::set<string> gen_and(const TreeDefine* root, int cur_level, int last_node_type);
    std::set<string> gen_assign(const TreeDefine* root, int cur_level, int last_node_type);
    std::set<string> gen_if(const TreeDefine* root, int cur_level, int last_node_type);
    std::set<string> gen_repeat(const TreeDefine* root, int cur_level, int last_node_type);
    std::set<string> gen_while(const TreeDefine* root, int cur_level, int last_node_type);
    std::set<string> gen_for(const TreeDefine* root, int cur_level, int last_node_type);
    std::set<string> gen_ek_case(const TreeDefine* root, int cur_level, int last_node_type);
    std::set<string> gen_sk_case(const TreeDefine* root, int cur_level, int last_node_type);
    std::set<string> gen_proc_id(const TreeDefine* root, int cur_level, int last_node_type);
    std::set<string> gen_proc_sys(const TreeDefine* root, int cur_level, int last_node_type);

public:
    // 符号表
    SymbolTable symbol_table;
    
    // 构造函数
    pcode_transformer(void);
    pcode_transformer(const SymbolTable& symbol_table);

    // 设置符号表
    void set_symbol_table(const SymbolTable& symbol_table);

    // 清空指令列表
    void clear_instruction(void);

    // 插入一条指令
    void insert_instruction(const st_ins& ins);
    void insert_instruction(ins_type op, int l, int d);

    /*  
        使用<<运算符插入指令
        e.g.
        pcode_transformer pt;
        st_ins ins(INS_INT, 0, 4);

        pt << ins;
    */ 
    pcode_transformer& operator<<(const st_ins& ins);

    /*  
        使用<<运算符完成读取AST 
        e.g.
        pcode_transformer pt;
        TreeDrfine ast;

        pt << ast;
    */ 
    void operator<<(const TreeDefine* AST);

    /*
        使用<<运算符输出指令到ostream
        e.g.
        cout << pt
    */
    friend ostream& operator<<(ostream& output, const pcode_transformer& pt);


};

#endif // __PCODE_HPP__